class Snake{
    // 表示蛇头的元素
    head:HTMLElement;
    // 表示蛇的身体的元素(包括蛇头)
    bodies:HTMLCollection; //会实时更新的
    // 获取蛇的容器
    element:HTMLElement;


    constructor(){
        this.element = document.getElementById('snake')!
        this.head = document.querySelector('#snake > div')! as HTMLElement;//只取一个 所以表示蛇头
        this.bodies =  this.element.getElementsByTagName('div'); //获取snake里面所有的div
    }

    //获取蛇X轴的坐标（蛇头坐标）
    get X(){
        return this.head.offsetLeft;
    }
    // 获取蛇的Y轴坐标（蛇头坐标）
    get Y(){
        return this.head.offsetTop;
    }

    //设置蛇头的X坐标
    set X(value:number){

        // 如果新值和旧值相同 则直接返回不再修改
        if(this.X === value){
            return;
        }

        // X的值合法范围是0-290之间 蛇撞墙了
        if(value < 0 || value > 290){
            //进入判断说明蛇撞墙了
            throw new Error('蛇撞墙了') //丢出异常
        }

        //修改X时，是在修改水平坐标，蛇在左右移动，蛇向左移动时， 不能向右掉头，反之亦然
        
        //首先先判断是否有第二节身体与第二节身体的水平坐标等于value坐标时 则发生了掉头
        if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value){ 
            
            console.log('水平方向发生了掉头')
            //如果发生了掉头，让蛇向反方向继续移动
            console.log(value)
            console.log('----------')
            console.log(this.X)
            if(value > this.X){
                
                //如果新值value大于旧值X，则说明蛇想要往向右走，此时发生掉头，不允许发生掉头应该使蛇继续向左走
                value = this.X -10;
            }else{
                //如果新值value小于旧值X，则说明蛇想要往向左走，此时发生掉头，不允许发生掉头应该使蛇继续向右走
                value = this.X +10;
            }

        }
        //移动身体
        this.moveBody()
        this.head.style.left = value + 'px';
        // 检查有没有撞到自己
        this.checkHeadBody();
    }

    //设置蛇头的Y坐标
    set Y(value:number){

         // 如果新值和旧值相同 则直接返回不再修改
        if(this.Y === value){
            return;
        }

        // Y的值合法范围是0-290之间 蛇撞墙了
        if(value < 0 || value > 290){
            //进入判断说明蛇撞墙了
            throw new Error('蛇撞墙了')
        }


        //修改Y时，是在修改垂直坐标，蛇在上下移动，蛇向上移动时， 不能向下掉头，反之亦然
         //首先先判断是否有第二节身体与第二节身体的垂直坐标等于value坐标时 则发生了掉头
         if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value){ 
            console.log(value)
            console.log(this.Y)

            if(value > this.Y){
                
                //如果新值value大于旧值Y，则说明蛇想要往向下走，此时发生掉头，不允许发生掉头应该使蛇继续向上走
                value = this.Y -10;
            }else{
                //如果新值value小于旧值Y，则说明蛇想要往向上走，此时发生掉头，不允许发生掉头应该使蛇继续向下走
                value = this.Y +10;
            }

        }

        
       
        //移动身体
        this.moveBody()
        this.head.style.top = value + 'px';
         // 检查有没有撞到自己(注意顺序调用问题)
         this.checkHeadBody();
    }


    //设置蛇增加身体的方法
    addBody(){
        //向element添加身体(添加div)
        this.element.insertAdjacentHTML("beforeend","<div></div>")
    }

    //头移动的时候 身体就要跟着移动了 所以要在头那里调用
    //添加一个蛇身体移动的方法
    moveBody(){
        /**
         *  将后边的身体设置为前边身体的位置
         *  举例子
         *      第四节 = 第三节的位置
         *      第三节 = 第二节的位置
         *      第二节 = 蛇头的位置
         * 
         */
        //遍历获取所有的身体 从后往前取
        for(let i=this.bodies.length-1; i>0; i--){
            //获取前边身体的位置
            let X = (this.bodies[i-1] as HTMLElement).offsetLeft; //这里需要对this.bodies[i-1]进行断言
            let Y = (this.bodies[i-1] as HTMLElement).offsetTop;

            // 将这个值设置到当前身体上
            (this.bodies[i] as HTMLElement).style.left = X + 'px';
            (this.bodies[i] as HTMLElement).style.top = Y + 'px';
        }

    }

    // 检查蛇头是否撞到身体的方法
    //判断头和身体有没有相撞
    checkHeadBody(){
        //获取所有的身体，检查其是否和蛇头的坐标重叠
        for(let i=1; i<this.bodies.length; i++){
            let bd = this.bodies[i] as HTMLElement
            if(this.X === bd.offsetLeft && this.Y === bd.offsetTop){
                //进入判断说明蛇头撞到了身体， 游戏结束
                throw new Error('撞到了自己！')
            }
        }
    }


}

export default Snake;